#include "lcd9696.h"
#include "OLEDFont.h"

/*引脚初始化*/
void OLED_SPI_Init(void)
{
	OLED_W_D0(0);
	OLED_W_D1(1);
	OLED_W_RES(1);
	OLED_W_DC(1);
	OLED_W_CS(1);
}

/**
  * @brief  SPI发送一个字节
  * @param  Byte 要发送的一个字节
  * @retval 无
  */
void OLED_SPI_SendByte(uint8_t Byte)
{
	uint8_t i;
	for (i = 0; i < 8; i++)
	{
		OLED_W_D1(Byte & (0x80 >> i));
		OLED_W_D0(1);
		OLED_W_D0(0);
	}
}

/**
  * @brief  OLED写命令
  * @param  Command 要写入的命令
  * @retval 无
  */
void OLED_WriteCommand(uint8_t Command)
{
	OLED_W_CS(0);
	OLED_W_DC(0);
	OLED_SPI_SendByte(Command);
	OLED_W_CS(1);
}

/**
  * @brief  OLED写数据
  * @param  Data 要写入的数据
  * @retval 无
  */
void OLED_WriteData(uint8_t Data)
{
	OLED_W_CS(0);
	OLED_W_DC(1);
	OLED_SPI_SendByte(Data);
	OLED_W_CS(1);
}

/**
  * @brief  OLED设置光标位置
  * @param  Y 以左上角为原点，向下方向的坐标
  * @param  X 以左上角为原点，向右方向的坐标
  * @retval 无
  */
void OLED_SetCursor(uint8_t Y, uint8_t X)
{
	OLED_WriteCommand(0xB0 | Y);					//设置Y位置
	OLED_WriteCommand(((X & 0xF0) >> 4)+0x11);	//设置X位置高4位
	OLED_WriteCommand((X & 0x0F)+0x00);			//设置X位置低4位
}

/**
  * @brief  OLED清屏
  * @param  无
  * @retval 无
  */
void OLED_Clear(void)
{  
	uint8_t i, j;
	for (j = 0; j < 12; j++)
	{
		OLED_SetCursor(j, 0);
		for(i = 0; i < 96; i++)
		{
			OLED_WriteData(0x00);
		}
	}
}

/**
  * @brief  OLED显示一个字符
  * @param  Line 行位置，范围：1~6
  * @param  Column 列位置，范围：1~11
  * @param  Char 要显示的一个字符，范围：ASCII可见字符
  * @retval 无
  */
void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char)
{      	
	uint8_t i;
	OLED_SetCursor((Line - 1) * 2, (Column - 1) * 8);		//设置光标位置在上半部分
	for (i = 0; i < 8; i++)
	{
		OLED_WriteData(OLED_F8x16[Char - ' '][i]);			//显示上半部分内容
	}
	OLED_SetCursor((Line - 1) * 2 + 1, (Column - 1) * 8);	//设置光标位置在下半部分
	for (i = 0; i < 8; i++)
	{
		OLED_WriteData(OLED_F8x16[Char - ' '][i + 8]);		//显示下半部分内容
	}
}

/**
  * @brief  OLED显示字符串
  * @param  Line 起始行位置，范围：1~6
  * @param  Column 起始列位置，范围：1~11
  * @param  String 要显示的字符串，范围：ASCII可见字符
  * @retval 无
  */
void OLED_ShowString(uint8_t Line, uint8_t Column, char *String)
{
	uint8_t i;
	for (i = 0; String[i] != '\0'; i++)
	{
		OLED_ShowChar(Line, Column + i, String[i]);
	}
}

/**
  * @brief  OLED次方函数
  * @retval 返回值等于X的Y次方
  */
uint32_t OLED_Pow(uint32_t X, uint32_t Y)
{
	uint32_t Result = 1;
	while (Y--)
	{
		Result *= X;
	}
	return Result;
}

/**
  * @brief  OLED显示数字（十进制，正数）
  * @param  Line 起始行位置，范围：1~6
  * @param  Column 起始列位置，范围：1~11
  * @param  Number 要显示的数字，范围：0~4294967295
  * @param  Length 要显示数字的长度，范围：1~10
  * @retval 无
  */
void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
	uint8_t i;
	for (i = 0; i < Length; i++)							
	{
		OLED_ShowChar(Line, Column + i, Number / OLED_Pow(10, Length - i - 1) % 10 + '0');
	}
}

/**
  * @brief  OLED显示数字（十进制，带符号数）
  * @param  Line 起始行位置，范围：1~6
  * @param  Column 起始列位置，范围：1~11
  * @param  Number 要显示的数字，范围：-2147483648~2147483647
  * @param  Length 要显示数字的长度，范围：1~10
  * @retval 无
  */
void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Length)
{
	uint8_t i;
	uint32_t Number1;
	if (Number >= 0)
	{
		OLED_ShowChar(Line, Column, '+');
		Number1 = Number;
	}
	else
	{
		OLED_ShowChar(Line, Column, '-');
		Number1 = -Number;
	}
	for (i = 0; i < Length; i++)							
	{
		OLED_ShowChar(Line, Column + i + 1, Number1 / OLED_Pow(10, Length - i - 1) % 10 + '0');
	}
}

/**
  * @brief  OLED显示数字（十六进制，正数）
  * @param  Line 起始行位置，范围：1~6
  * @param  Column 起始列位置，范围：1~11
  * @param  Number 要显示的数字，范围：0~0xFFFFFFFF
  * @param  Length 要显示数字的长度，范围：1~12
  * @retval 无
  */
void OLED_ShowHexNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
	uint8_t i, SingleNumber;
	for (i = 0; i < Length; i++)							
	{
		SingleNumber = Number / OLED_Pow(16, Length - i - 1) % 16;
		if (SingleNumber < 10)
		{
			OLED_ShowChar(Line, Column + i, SingleNumber + '0');
		}
		else
		{
			OLED_ShowChar(Line, Column + i, SingleNumber - 10 + 'A');
		}
	}
}

/**
  * @brief  OLED显示数字（二进制，正数）
  * @param  Line 起始行位置，范围：1~6
  * @param  Column 起始列位置，范围：1~11
  * @param  Number 要显示的数字，范围：0~1111 1111 1111 1111
  * @param  Length 要显示数字的长度，范围：1~12
  * @retval 无
  */
void OLED_ShowBinNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
	uint8_t i;
	for (i = 0; i < Length; i++)							
	{
		OLED_ShowChar(Line, Column + i, Number / OLED_Pow(2, Length - i - 1) % 2 + '0');
	}
}

//显示16*16汉字
//x,y:起点坐标 Line:1-6 Column:1-96
//*cn:字符串起始地址		  
void OLED_Show_16HZ(uint8_t Line, uint8_t Column, uint8_t *cn)
{
	u8 j, x1, x2, wordNum;
	
	if(Column>96||Line>8)return;//超出范围了

	Line--;	//0开始计算
	Column--;
	
	Line *= 2;
	Line += 0xB0;	   			//求取Y坐标的值

	while ( *cn != '\0')	 //在C语言中字符串结束以‘\0’结尾
	{
		x1 = (Column >> 4) & 0x0F;   //由于X坐标要两句命令，分高低4位，所以这里先取出高4位
		x2 = Column & 0x0F;          //去低四位

		OLED_WriteCommand(Line);	//页地址 y坐标
		OLED_WriteCommand(0x11+x1);	//列高字节地址 x坐标
		OLED_WriteCommand(0x00+x2);	//列低字节地址

		for (wordNum=0; wordNum<30; wordNum++)
		{
			//--查询要写的字在字库中的位置--//
			if ((CnChar16x16[wordNum].Index[0] == *cn)&&(CnChar16x16[wordNum].Index[1] == *(cn+1)))
			{
				for (j=0; j<32; j++) //写一个字
				{
					if (j == 16)	 //由于16X16用到两个Y坐标，当大于等于16时，切换坐标
					{
						OLED_WriteCommand(Line+1);	//页地址 y坐标
						OLED_WriteCommand(0x11+x1);	//列高字节地址 x坐标
						OLED_WriteCommand(0x00+x2);	//列低字节地址
					}
					OLED_WriteData(CnChar16x16[wordNum].Msk[j]);
				}
				Column += 16;
			}
		}
		cn += 2;	//下一个字
	}
}

/**
  * @brief  OLED初始化
  * @param  无
  * @retval 无
  */
void OLED_Init(void)
{
	delay_ms(300);
	
	OLED_SPI_Init();			//端口初始化
	
	OLED_WriteCommand(0xAE); //关闭显示 
	OLED_WriteCommand(0xD5); //设置显示时钟分频比/振荡器频率
	OLED_WriteCommand(0xe1); 
	OLED_WriteCommand(0xA8); //设置多路复用率
	OLED_WriteCommand(0x5F); /*duty = 1/64*/ 
	OLED_WriteCommand(0xD3); //设置显示偏移
	OLED_WriteCommand(0x00); 
	OLED_WriteCommand(0x40); //设置显示开始行
	OLED_WriteCommand(0xA1); //设置左右方向，0xA1正常 0xA0左右反置
	OLED_WriteCommand(0xC0); //设置上下方向，0xC8正常 0xC0上下反置
	OLED_WriteCommand(0xDA); //设置COM引脚硬件配置
	OLED_WriteCommand(0x12); 
	OLED_WriteCommand(0x81); //设置对比度控制
	OLED_WriteCommand(0x67); /*128*/ 
	OLED_WriteCommand(0xD9); //设置预充电周期
	OLED_WriteCommand(0x22); 
	OLED_WriteCommand(0xdb); //设置VCOMH取消选择级别
	OLED_WriteCommand(0x20); 
	OLED_WriteCommand(0xA4); //设置整个显示打开/关闭
	OLED_WriteCommand(0xA6); //设置正常/倒转显示
	OLED_WriteCommand(0xB0); //设置充电泵
	OLED_Clear();
	OLED_WriteCommand(0xAF); //开启显示
}
